package com.dzsw.javabase.optional;

import cn.hutool.json.JSONUtil;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class OptionalSample {

    public static void main(String[] args) {
        // 参考： https://blog.csdn.net/qq_33697094/article/details/126344978

        // 1. create of ofNullable
        // of 接收的值不能为 null ，否则会报空指针异常。
//        Student stu = null;
        Student stu = new Student("Jack", 80);
        Optional<Student> optional = Optional.of(stu);
        // ofNullable 的参数可以为 null ，不会抛出异常，但在使用 get 获取的时候会抛出异常。
        optional = Optional.ofNullable(stu);

        // 2. 判空 isPresent isEmpty
        System.out.println("optional.isPresent(), 不为空 != null , >> " + optional.isPresent());
        // java 11 开始有 isEmpty
        System.out.println("optional.isEmpty(), 为空 == null , >> " + optional.isEmpty());

        // 3. 判空后的条件动作，ifPresent ifPresentOrElse
        // if (stu != null) {}
        optional.ifPresent(item -> {
            System.out.println("optional.ifPresent, stu 不为空, >> " + JSONUtil.toJsonStr(item));
        });
        // if (stu != null) {} else {}
        optional.ifPresentOrElse((item) -> {
            System.out.println("optional.ifPresentOrElse, stu 不为空, >> " + JSONUtil.toJsonStr(item));
        }, () -> {
            System.out.println("optional.ifPresentOrElse, stu 为空");
        });

        // 4. 获取对象值 get
        // 如果 stu 为 null ，在使用 get 时会抛出 NoSuchElementException
        // 面的写法只是样例，并不可取，后面会有几种代替 isPresent()和 get()
        if (optional.isPresent()) {
            System.out.println("optional.isPresent(), stu 不为空, >> " + JSONUtil.toJsonStr(optional.get()));
        }

        // 5. orElse orElseGet
        // 可替代 get 操作，并且可以避免 NoSuchElementException
        // 先执行 orElse 里的语句，然后判断 optional 里的值是否为空，不为空返回 optional 里的对象，为空返回 orElse 里语句的值。
        Student stu1 = new Student("Rose", 24);
//        Student stu1 = null;
        optional = Optional.ofNullable(stu1);
        Student stu2 = optional.orElse(new Student("Susan", 26));
        System.out.println("optional.orElse, " + JSONUtil.toJsonStr(stu2));
        // 先判断 optional 里的值是否为空，为空则执行后面的函数并赋值。
        stu2 = optional.orElseGet(new Supplier<Student>() {
            @Override
            public Student get() {
                System.out.println("orElseGet method running...");
                return new Student("Susan", 26);
            }
        });
        System.out.println("optional.orElseGet, >> " + JSONUtil.toJsonStr(stu2));

        // 6. or() 操作
        // 行为跟 orElseGet 一致，返回值是一个 Optional 对象
//        String str = null;
        String str = "expected";
        Optional<String> optionalStr = Optional.ofNullable(str);
        Optional<String> resultStr = optionalStr.or(new Supplier<Optional<? extends String>>() {
            @Override
            public Optional<? extends String> get() {
                System.out.println("or method running...");
                return Optional.of("default string");
            }
        });
        System.out.println("optionalStr.or, >> " + resultStr.get());

        // 7. filter() 过滤
        // 将谓词作为参数并返回一个 Optional 对象，如果参数为空不会抛出异常。
//        Integer year = 2022;
        Integer year = null;
        Optional<Integer> optionalYear = Optional.ofNullable(year);
        boolean is2022 = optionalYear.filter(y -> y == 2022).isPresent();
        boolean is2023 = optionalYear.filter(y -> y == 2023).isPresent();
        System.out.println("optionalYear.filter, is2022 >> " + is2022 + ", is2023 >> " + is2023);

        // 8. map() 映射
        // 使用 Optional 可以使普通类使用 map 映射方法操作类
        // 8.1 获取companyNames的长度
        List<String> companyNameList = Arrays.asList("paypal", "oracle", "", "microsoft", "", "apple");
        Optional<List<String>> optionalList = Optional.ofNullable(companyNameList);
        int length = optionalList.map(List::size).orElse(0);
        System.out.println("optionalList.map(List::size) >> " + length);
        // 8.2 trim
        String pwd = " this is password ";
        Optional<String> pwdOptional = Optional.ofNullable(pwd);
        boolean isRight = pwdOptional.map(String::trim).filter(ss -> ss.equals("pwd")).isPresent();
        System.out.println("pwdOptional.map(String::trim).filter(ss -> ss.equals(\"pwd\")) >> " + isRight );
        // 8.3 标准映射处理
        optional = Optional.ofNullable(stu);
        String stuName = optional
                .map(Student::getName)
                .map(name -> name.toUpperCase())
                .orElse("");
        System.out.println("optional.map, >> " + stuName);
        // 8.4 联合使用 map 和 filter
        stu.setFee(13);
        System.out.println("feeIsInRange >> " + feeIsInRange(stu) + ", " + JSONUtil.toJsonStr(stu));

        // 9. flatMap() 解包操作
        Person p = new Person();
        p.setName("Jack").setAge(80).setPwd("pwd");
        Optional<Person> optionalPerson = Optional.ofNullable(p);
        String strName = optionalPerson.flatMap(Person::getName).orElse("");
        System.out.println("optionalPerson.flatMap(Person::getName) >> " + strName);

        // 10. stream()
        // java9 后允许我们将 Optional 实例视为 Stream
        List<String> collect = optionalList.stream()
                .flatMap(Collection::stream)
                .filter(item -> item.length() >= 6)
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("optionalList.stream() >> " + JSONUtil.toJsonStr(collect));
    }

    public static boolean feeIsInRange(Student stu) {
        return Optional.ofNullable(stu)
                .map(Student::getFee)
                .filter(fee -> fee >= 10 && fee <=15)
//                .filter(fee -> fee >= 10)
//                .filter(fee -> fee <= 15)
                .isPresent();
    }


}
